ID); if (is_array($slides)) $slides = current($slides)['slide_image']; endif; if ($image_id = @array_shift(array_shift(tr_posts_field('builder'))['hero']['slides'])['slide_image']) : $slides = $image_id; else : global $post; $slides = tr_posts_field('slides', $id); if (is_array($slides)) $slides = current($slides)['slide_image']; endif; if (!$slides) $slides = get_post_thumbnail_id(); if ($only_id) return $slides; return get_responsive_image($slides, $size, 'image-progressive'); } function get_responsive_image($id, $size = '', $class = '', $alt = '', $link = '') { if (empty($id)) $id = get_the_ID(); if (empty($size)) $size = 'wide'; $html = ''; $sizes = "(min-width: 740px) 740w, 50%, 1280w"; $image = wp_get_attachment_image_url($id, $size); $srcset = wp_get_attachment_image_srcset($id, $size); //$preload = wp_get_attachment_image_url($id, 'preload'); $preload = wp_get_attachment_image_url($id, $size); if (!$alt) $alt = get_post_meta($id, '_wp_attachment_image_alt', true) ?: get_the_title(); if (!$class or $class == 'swiper-lazy') { $class = "swiper-lazy"; $html .= << HTML; return $html; } else { $html .= << {$alt} HTML; return $html; }; } function add_custom_src_image_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) { $image_size_name = 'square'; // add_image_size('square500', 500, 500, true); $breakpoint = 740; $upload_dir = wp_upload_dir(); $img_url = $image_src; if (isset($image_meta['sizes'][$image_size_name])) $img_url = $upload_dir['baseurl'] . '/' . str_replace(basename($image_meta['file']), $image_meta['sizes'][@$image_size_name]['file'], $image_meta['file']); $sources[$image_size_name] = array( 'url' => $img_url ?: $image_src, 'descriptor' => 'w', 'value' => $breakpoint, ); return $sources; } add_filter('wp_calculate_image_srcset', 'add_custom_src_image_srcset', 10, 5); /** * Content related */ function the_content_split($content = '') { if (empty($content)) { global $post; $content = $post->post_content; } $html = ''; // $content = esc_html($content); // $content = explode('', $content); $content = explode('', $content); if (!@$content[1]) $content[1] = null; return $content; } function get_term_excerpt($count = 200, $term_id = '', $readmore = true) { $term = get_term($term_id); $label = pll__('Read more'); $template_directory = get_template_directory_uri(); $permalink = get_term_link($term); if (empty($term->description)) { if (!empty($post->description)) : $excerpt = (isset($post) ? $post->description : ''); else : if (!empty(tr_posts_field('builder'))) : foreach (tr_posts_field('builder') as $component) { if (isset($component['content'])) : $excerpt = $component['content']['content']; elseif (isset($component['tiles'])) : $excerpt = $component['tiles']['content']; endif; } endif; endif; } else { $excerpt = (isset($post) ? $post->description : ''); } $excerpt = strip_tags(@$excerpt); $excerpt = substr($excerpt, 0, $count); $excerpt = substr($excerpt, 0, (int) strripos($excerpt, " ")); $excerpt = $excerpt . '...'; $readmore = << {$label} Scroll down HTML; if ($readmore === true) $excerpt .= $readmore; return $excerpt; } function get_excerpt($count = 200, $post_id = '', $readmore = true) { $post = get_post($post_id); $label = pll__('Read more'); $template_directory = get_template_directory_uri(); $permalink = get_permalink($post_id); if (empty($post->post_excerpt)) { if (!empty($post->post_content)) : $excerpt = get_the_excerpt(); else : if (!empty(tr_posts_field('builder'))) : foreach (tr_posts_field('builder') as $component) { if (isset($component['content'])) : $excerpt = $component['content']['content']; elseif (isset($component['tiles'])) : $excerpt = $component['tiles']['content']; endif; } endif; endif; } else { $excerpt = $post->post_excerpt; } $excerpt = strip_tags(@$excerpt); $excerpt = substr($excerpt, 0, $count); $excerpt = substr($excerpt, 0, (int) strripos($excerpt, " ")); $excerpt = $excerpt . '...'; $readmore = << {$label} Scroll down HTML; if ($readmore === true) $excerpt .= $readmore; return $excerpt; } /** * Theme related */ function isAjax() { return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'; } function get_charter_permalink($id = null) { global $post; if (!$id) $id = pll_get_post($post->id, pll_current_language()); $link = get_post_permalink($id); // $link = str_replace('yacht', 'yacht-charter', $link); $link = preg_replace('(\Wyacht\W)', '/yacht-charter/', $link); return $link; } function wn_get_available_link() { global $post; if (get_query_var('charter') == true) { if (tr_posts_field('available_for_sale', $post->ID)) { $label = pll__('also available for sale', 'wn'); $url = get_post_permalink(pll_get_post($post->ID, pll_current_language())); } else { $label = pll__('not available for sale', 'wn'); $url = '#'; } } else { if (tr_posts_field('available_for_charter', $post->ID)) { $label = pll__('also available for charter', 'wn'); $url = get_charter_permalink(); } else { $label = pll__('not available for charter', 'wn'); $url = '#'; } } $html = << {$label} HTML; return $html; } function formatPhone($data = '') { if (!is_string($data)) return null; if (preg_match('/^\+\d(\d{3})(\d{3})(\d{2})(\d{2})$/', $data, $matches)) { $result = '+7 ' . $matches[1] . ' ' . $matches[2] . ' ' . $matches[3] . ' ' . $matches[4]; return $result; } else { return $data; } } add_filter('date_i18n', 'russify_months', 11, 2); /** * Русифицирует месяца и недели в дате. * Функция для фильтра date_i18n. * @param строка $date Дата в принятом формате * @param строка $req_format Формат передаваемой даты * @return Дату в русском формате */ function russify_months($date, $req_format) { // в формате есть "строковые" неделя или месяц if (!preg_match('/[FMlS]/', $req_format)) return $date; $replace = array( 'Январь' => 'января', 'Февраль' => 'февраля', 'Март' => 'марта', 'Апрель' => 'апреля', 'Май' => 'мая', 'Июнь' => 'июня', 'Июль' => 'июля', 'Август' => 'августа', 'Сентябрь' => 'сентября', 'Октябрь' => 'октября', 'Ноябрь' => 'ноября', 'Декабрь' => 'декабря', 'Янв' => 'янв.', 'Фев' => 'фев.', 'Мар' => 'март', 'Апр' => 'апр.', 'Май' => 'май', 'Июн' => 'июнь', 'Июл' => 'июль', 'Авг' => 'авг.', 'Сен' => 'сен.', 'Окт' => 'окт.', 'Ноя' => 'ноя.', 'Дек' => 'дек.', 'January' => 'января', 'February' => 'февраля', 'March' => 'марта', 'April' => 'апреля', 'May' => 'мая', 'June' => 'июня', 'July' => 'июля', 'August' => 'августа', 'September' => 'сентября', 'October' => 'октября', 'November' => 'ноября', 'December' => 'декабря', 'Jan' => 'янв.', 'Feb' => 'фев.', 'Mar' => 'март.', 'Apr' => 'апр.', 'May' => 'мая', 'Jun' => 'июня', 'Jul' => 'июля', 'Aug' => 'авг.', 'Sep' => 'сен.', 'Oct' => 'окт.', 'Nov' => 'нояб.', 'Dec' => 'дек.', 'Sunday' => 'воскресенье', 'Monday' => 'понедельник', 'Tuesday' => 'вторник', 'Wednesday' => 'среда', 'Thursday' => 'четверг', 'Friday' => 'пятница', 'Saturday' => 'суббота', 'Sun' => 'вос.', 'Mon' => 'пон.', 'Tue' => 'вт.', 'Wed' => 'ср.', 'Thu' => 'чет.', 'Fri' => 'пят.', 'Sat' => 'суб.', 'th' => '', 'st' => '', 'nd' => '', 'rd' => '', ); $date = strtr($date, $replace); //if( function_exists('mb_strtolower') ) $date = mb_strtolower( $date ); return $date; } /** * Search form */ add_filter('get_search_form', 'yacht_search_form'); function yacht_search_form($form) { $lang = pll_current_language() == 'ru' ? 'ru' : ''; $action = esc_url(home_url('/')) . $lang . '/search/'; $label = pll__('Search for', 'wn'); $label_yachts = pll__('In yachts', 'wn'); $label_other = pll__('Everywhere', 'wn'); $reader = pll__('Query for search', 'wn'); $form = ' '; return $form; } function get_yacht_search_query($escaped = true) { /** * Filters the contents of the yacht search query variable. * @param mixed $search Contents of the search query variable. */ $query = apply_filters('get_search_query', get_query_var('search_input')); if ($escaped) { $query = esc_attr($query); } return $query; } function pagination($query) { if ((!$query)) : global $wp_query; $query = $wp_query; else : $query = $query; endif; $big = 999999999; $total = isset($query->max_num_pages) ? $query->max_num_pages : 1; $args = array( 'format' => '?page=%#%', 'current' => max(1, get_query_var('paged')), 'prev_next' => true, 'prev_text' => 'Previous page', 'next_text' => 'Next page', 'total' => $total ); if (get_option('permalink_structure')) : $args['base'] = str_replace($big, '%#%', get_pagenum_link($big)); else : $args['base'] = add_query_arg('page', '%#%'); endif; // echo previous_posts_link('Newer posts'); echo paginate_links($args); // echo next_posts_link('Older posts'); } /** * Contact form shortcode for destinations list in cards */ add_filter('wpcf7_form_elements', 'do_shortcode'); // Добавив такой хук, мы можем создать обычный шорткод WordPress с помощью add_shortcode() и он будет работать в форме CF7: function destinations_cards_cf7_func() { return "Привет! Я шоркод для Contact Form 7!"; } add_shortcode('destinations_cards', 'destinations_cards_cf7_func'); /** * Invalidate the filter-range / destination-region caches (see * FilterController::clearRangesCache() and * QueryController::clearDestinationRegionsCache()) whenever a yacht or * destination is saved, trashed, or permanently deleted, so edits show up * immediately instead of waiting for the transients' TTL to expire. */ function wn_clear_listing_caches($post_id) { $post_type = get_post_type($post_id); if (!in_array($post_type, array('yacht', 'destination'), true)) { return; } if (class_exists('FilterController')) { FilterController::clearRangesCache(); } if ($post_type === 'destination' && class_exists('QueryController')) { QueryController::clearDestinationRegionsCache(); } } add_action('save_post', 'wn_clear_listing_caches'); add_action('trashed_post', 'wn_clear_listing_caches'); add_action('untrashed_post', 'wn_clear_listing_caches'); add_action('before_delete_post', 'wn_clear_listing_caches'); setMessages([ 'first-name' => 'Введите ваше имя', 'last-name' => 'Введите вашу фамилию', 'email' => 'Введите вашу электронную почту', 'phone' => 'Укажите ваш номер телефона', 'acceptance-gdpr' => 'Согласитесь с политикой конфиденциальности', 'form_token' => 'Are you human?', 'enquiry_type' => 'Specify your nature of enquiry' // etc ]); } else { $validator->setMessages([ 'first-name' => 'Enter you first name', 'last-name' => 'Enter your last name', 'email' => 'Enter your email', 'phone' => 'Enter your phone number', 'acceptance-gdpr' => 'Accept privacy policy', 'form_token' => 'Are you human?', 'enquiry_type' => 'Specify your nature of enquiry' // etc ]); } } return $validator; } function requestCharter_action() { $data = $_POST; // ! token check if (wp_verify_nonce($_GET['wn_nonce'], 'wn_nonce')) { $validator = createValidator(); $validation = $validator->make($_POST + $_FILES, [ 'first-name' => 'required', 'last-name' => 'required', 'email' => 'required|email', 'acceptance-gdpr' => 'required', 'form_token' => 'required' ]); // then validate $validation->validate(); header('Content-type: application/json'); if ($validation->fails()) { // not acceptable http_response_code(206); // handling errors $errors = $validation->errors(); echo json_encode($errors->firstOfAll()); exit; } else { if (!validate_recaptcha($data['form_token'])) { echo json_encode(['generic' => 'Are you a robot? Please try again!']); exit; } unset($data['form_token']); // OK http_response_code(200); // validation passes send_formdata_mail('New charter request', $data); } } } /** * Callback form handler on server side * * @input $_POST * @output {status, message} */ add_action('wp_ajax_callbackForm_action', 'callbackForm_action'); add_action('wp_ajax_nopriv_callbackForm_action', 'callbackForm_action'); function callbackForm_action() { $data = $_POST; // ! token check if (wp_verify_nonce($_GET['wn_nonce'], 'wn_nonce')) { $validator = createValidator(); $validation = $validator->make($_POST + $_FILES, [ 'phone' => 'required|numeric', 'acceptance-gdpr' => 'required', 'form_token' => 'required' ]); // then validate $validation->validate(); header('Content-type: application/json'); if ($validation->fails()) { // not acceptable http_response_code(206); // handling errors $errors = $validation->errors(); echo json_encode($errors->firstOfAll()); exit; } else { if (!validate_recaptcha($data['form_token'])) { echo json_encode(['generic' => 'Are you a robot? Please try again!']); exit; } unset($data['form_token']); // OK http_response_code(200); // validation passes send_formdata_mail('New callback request', $data); } } } /** * Contact form handler on server side * * @input $_POST * @output {status, message} */ add_action('wp_ajax_contactForm_action', 'contactForm_action'); add_action('wp_ajax_nopriv_contactForm_action', 'contactForm_action'); function contactForm_action() { $data = $_POST; // ! token check if (wp_verify_nonce($_GET['wn_nonce'], 'wn_nonce')) { $validator = createValidator(); $validation = $validator->make($_POST + $_FILES, [ 'first-name' => 'required', 'last-name' => 'required', 'email' => 'required|email', 'acceptance-gdpr' => 'required', 'form_token' => 'required', 'enquiry_type' => 'required' ]); // then validate $validation->validate(); header('Content-type: application/json'); if ($validation->fails()) { // not acceptable http_response_code(206); // handling errors $errors = $validation->errors(); echo json_encode($errors->firstOfAll()); exit; } else { if (!validate_recaptcha($data['form_token'])) { echo json_encode(['generic' => 'Are you a robot? Please try again!']); exit; } unset($data['form_token']); // OK http_response_code(200); // validation passes send_formdata_mail('New contact form request', $data); } } } /** * Subscribe form handler on server side * * @input $_POST * @output {status, message} */ add_action('wp_ajax_subscribeForm_action', 'subscribeForm_action'); add_action('wp_ajax_nopriv_subscribeForm_action', 'subscribeForm_action'); function subscribeForm_action() { $data = $_POST; // ! token check if (wp_verify_nonce($_GET['wn_nonce'], 'wn_nonce')) { $validator = createValidator(); $validation = $validator->make($_POST + $_FILES, [ 'email' => 'required|email', 'acceptance-gdpr' => 'required', 'contact_type' => 'required', 'form_token' => 'required' ]); // then validate $validation->validate(); header('Content-type: application/json'); if ($validation->fails()) { // not acceptable http_response_code(206); // handling errors $errors = $validation->errors(); echo json_encode($errors->firstOfAll()); exit; } else { if (!validate_recaptcha($data['form_token'])) { echo json_encode(['generic' => 'Are you a robot? Please try again!']); exit; } unset($data['form_token']); // OK http_response_code(200); // validation passes send_formdata_mail('New subscription', $data); } } } function validate_recaptcha($token) { $data = array( 'secret' => "6LcMWQcaAAAAAD3o-rcYTO29tg5JnFUP0ukmwns-", 'response' => $token ); $verify = curl_init(); curl_setopt($verify, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify"); curl_setopt($verify, CURLOPT_POST, true); curl_setopt($verify, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($verify, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($verify, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($verify), true); return $response['success'] && $response['score'] >= 0.5; } function send_formdata_mail($subject, $data) { $to = false; if (isset($data['post_type'])) { $to = 'info@westnautical.com'; switch ($data['post_type']) { case 'yacht': $to = 'charter@westnautical.com'; break; case 'vacancy': $to = 'crew@westnautical.com'; break; case 'service_wn': $post = get_post($_POST['post_id']); if ($post && stripos($post->name, 'sell') !== false) { $to = 'sales@westnautical.com'; } break; } unset($data['post_type']); unset($data['post_id']); } if (isset($_POST['enquiry_type'])) { $to = 'info@westnautical.com'; switch ($_POST['enquiry_type']) { case 'crew': $to = 'crew@westnautical.com'; break; case 'sales': $to = 'info@westnautical.com'; break; case 'charter': $to = 'info@westnautical.com'; break; case 'management': $to = 'info@westnautical.com'; break; } } $message = ''; foreach ($data as $key => $value) { $key = sanitize_text_field($key); $value = sanitize_text_field($value); $message .= "$key: $value\n"; } $log_path = get_template_directory() . '/contacts/' . str_replace('@', '-', $to) . '.log'; file_put_contents($log_path, sprintf('%s: %s', date('d/m/Y H:i'), $subject) . PHP_EOL, FILE_APPEND); file_put_contents($log_path, $message, FILE_APPEND); file_put_contents($log_path, '=====================================================================' . PHP_EOL . PHP_EOL, FILE_APPEND); if ($to === false) { if (tr_options_field('system_notification_email_address')): $to = tr_options_field('system_notification_email_address'); else: $to = 'info@westnautical.com'; endif; } $header = []; $headers[] = 'From: West Nautical ' . "\r\n"; if (isset($data['email'])) { $headers[] = 'Reply-To:' . $data['email']; } $result = wp_mail($to, $subject, $message, $headers); //$result = wp_mail('gavin@teamvalleyweb.co.uk', $subject, $message, $headers); } ['min' => 1, 'max' => 20000000] ]; public $prices = [ 'eur' => [ 'range' => ['min' => 1, 'max' => 20000000] ], 'gbp' => [ 'range' => ['min' => 1, 'max' => 20000000] ], 'usd' => [ 'range' => ['min' => 1, 'max' => 20000000] ], 'rub' => [ 'range' => ['min' => 1, 'max' => 20000000] ] ]; public $length = [ 'range' => ['min' => 0, 'max' => 50] ]; public $year = [ 'range' => ['min' => 2000, 'max' => 2020] ]; public $location = [ 'range' => [0 => 'Все местоположения'] ]; public $search_input = [ 'current' => '' ]; public $debug = []; /** * Names of the instance properties populated by the expensive block * below (a full, unbounded `posts_per_page => -1` scan of every * "yacht" post, followed by a get_post_meta()/taxonomy lookup per post * per filter dimension). These describe the *available filter ranges* * (min/max price, brand list, region list, etc.) - they only change * when yacht/destination data changes, not per-visitor, so they are * safe to cache across requests instead of recomputing on every single * page view of the yacht listing / search / charter pages. */ const CACHED_RANGE_PROPS = ['length', 'year', 'location', 'region', 'brands', 'guests', 'types', 'charter', 'prices']; function __construct() { $this->brands['range'] = [0 => pll__('All brands', 'wn')]; $this->guests['range'] = [0 => pll__('Any', 'wn')]; $this->types['range'] = [0 => pll__('Any', 'wn')]; $this->region['range'] = [0 => pll__('Any', 'wn')]; $this->guests['range'] = [0 => pll__('Any', 'wn')]; $this->currency = get_query_var('currency') ?: 'eur'; $this->debug[] = 'get query var currency'; $this->setSettings(); $cache_key = $this->getRangesCacheKey(); $cached = get_transient($cache_key); if (is_array($cached) && count(array_diff(self::CACHED_RANGE_PROPS, array_keys($cached))) === 0) { foreach (self::CACHED_RANGE_PROPS as $prop) { $this->$prop = $cached[$prop]; } $this->debug[] = 'filter ranges loaded from transient cache'; } else { $this->query = $this::getFullQuery(); $this::setMinMax(); $this::getLocations(); $this::getRegions(); $this::getYearRange(); $this->brands['range'] = $this::getBrands(); $this->guests['range'] = $this::getGuests(); $this->types['range'] = $this::getTypes(); $this::getCharterRates(); $this::getPrices(); unset($this->query); $this->debug[] = 'full query was unset'; $to_cache = []; foreach (self::CACHED_RANGE_PROPS as $prop) { $to_cache[$prop] = $this->$prop; } // 6 hour TTL as a safety net; save_post/delete_post hooks // (registered in includes/init/functions.php) clear this // immediately whenever a yacht or destination is edited, so // the TTL is a backstop, not the primary invalidation path. set_transient($cache_key, $to_cache, 6 * HOUR_IN_SECONDS); } $this::setPostData(); } /** * Cache key for the computed filter ranges. Ranges only vary by * currency (prices) and current language (region/brand names go * through Polylang translation helpers), so both are baked into the key. */ private function getRangesCacheKey() { $lang = function_exists('pll_current_language') ? pll_current_language() : 'default'; return 'wn_filter_ranges_' . md5($this->currency . '|' . $lang); } /** * Clear every cached filter-range variant. Hooked to save/delete of * "yacht" and "destination" posts (see includes/init/functions.php) * since editing either can change the available filter ranges. */ public static function clearRangesCache() { global $wpdb; $like = $wpdb->esc_like('_transient_wn_filter_ranges_') . '%'; $names = $wpdb->get_col($wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", $like )); foreach ($names as $name) { delete_option($name); delete_option(str_replace('_transient_', '_transient_timeout_', $name)); } } /* * @input Getting post data * @return [Array] * @since 1.0.0 */ private function setSettings() { if (is_int(tr_options_field('filter_min_year'))) $this->year['range']['min'] = intval(tr_options_field('filter_min_year')); if (is_int(tr_options_field('filter_max_year'))) $this->year['range']['max'] = intval(tr_options_field('filter_max_year')); } private function setPostData() { $postdata = $_GET; $this->charter['current']['min'] = isset($postdata['charter_min']) ? intval($postdata['charter_min']) : $this->charter['range']['min']; $this->charter['current']['max'] = isset($postdata['charter_max']) ? intval($postdata['charter_max']) : $this->charter['range']['max']; $this->prices['current']['min'] = isset($postdata['price_min']) ? intval($postdata['price_min']) : $this->prices['range']['min']; $this->prices['current']['max'] = isset($postdata['price_max']) ? intval($postdata['price_max']) : $this->prices['range']['max']; $this->length['current']['min'] = isset($postdata['length_min']) ? intval($postdata['length_min']) : $this->length['range']['min']; $this->length['current']['max'] = isset($postdata['length_max']) ? intval($postdata['length_max']) : $this->length['range']['max']; $this->year['current']['min'] = isset($postdata['year_min']) ? intval($postdata['year_min']) : $this->year['range']['min']; $this->year['current']['max'] = isset($postdata['year_max']) ? intval($postdata['year_max']) : $this->year['range']['max']; $this->location['current'] = isset($postdata['location']) ? $postdata['location'] : $this->location['range'][0]; $this->region['current'] = isset($postdata['region']) ? $postdata['region'] : $this->region['range'][0]; $this->brands['current'] = isset($postdata['brands']) ? $postdata['brands'] : $this->brands['range'][0]; $this->guests['current'] = isset($postdata['guests']) ? $postdata['guests'] : $this->guests['range'][0]; $this->types['current'] = isset($postdata['type']) ? $postdata['type'] : $this->types['range'][0]; $this->types['current'] = isset($postdata['type']) ? $postdata['type'] : $this->types['range'][0]; $this->search_input = isset($postdata['search_input']) ? $postdata['search_input'] : ''; $this->currency = get_query_var('currency') ?? self::DEFAULT_CURRENCY; set_query_var('currency', $this->currency); } /* * Sets mins&maxes for filter from posts * * @output */ private function getFullQuery() { if (!isset($this->query)) { $builder = new Builder(); $args = $builder->addPostType('yacht')->getParameters(); $args['posts_per_page'] = '-1'; $query = new WP_Query($args); $this->debug[] = 'get full query'; return $query; } else { $this->debug[] = 'full query was already set'; return $query; } } private function setMinMax() { foreach ($this->query->posts as $key => $post) { // $prices[$key] = intval(get_post_meta($post->ID, 'price_cc_' . $this->currency, true)); $year[$key] = intval(get_post_meta($post->ID, 'year', true)); $length[$key] = intval(str_replace(',', '.', get_post_meta($post->ID, 'length', true))); } $this->length['range'] = $this::roundLength($length); $this->year['range']['max'] = tr_options_field('filter_max_year') ?: 2020; $this->debug[] = 'min max values loaded'; } public function getPrices() { foreach ($this->prices as $currency => $range) { foreach ($this->query->posts as $key => $post) { $values[$currency][] = intval(get_post_meta($post->ID, 'price_cc_' . $currency, true) ?: [0]); } $values[$currency] = array_filter($values[$currency]); $values[$currency] = array_unique($values[$currency]); $prices[$currency]['range']['min'] = intval(min($values[$currency])) ?? 0; $prices[$currency]['range']['max'] = intval(max($values[$currency])); // $prices[$currency]['range']['min'] = $this->roundPrices($prices[$currency]['range']['min'], 100); // $prices[$currency]['range']['max'] = $this->roundPrices($prices[$currency]['range']['max'], 100); } $this->debug[] = 'prices in all currencies loaded'; $this->prices = $prices; $this->prices['range'] = $prices[$this->currency]['range']; $this->prices['current'] = $prices[$this->currency]['range']; // echo '
';
        // var_dump($this->prices);
        // echo '
'; } public function roundPrices($value, $profit) { $round_to = 20; $round_to = intval($round_to) / 100; $price = $value * floatval($profit) / 100; $price = ceil($price); $count = strlen((string) $price); $price = round($price, floor(-$count * $round_to), PHP_ROUND_HALF_UP); // round setting return $price; } public function getCharterRates() { foreach ($this->query->posts as $key => $post) { $values[] = intval(get_post_meta($post->ID, 'charter_rate', true) ?: [0]); } $values = array_filter($values); $values = array_unique($values); $charter_rates['range']['min'] = intval(min($values)); $charter_rates['range']['max'] = intval(max($values)); $charter_rates['range']['min'] = $this->roundPrices($charter_rates['range']['min'], 100); $charter_rates['range']['max'] = $this->roundPrices($charter_rates['range']['max'], 100); $this->debug[] = 'charter rates loaded'; $this->charter = $charter_rates; } public function getLocations() { $locations = []; foreach ($this->query->posts as $key => $post) { $country = get_post_meta($post->ID, 'country'); $country = array_shift($country); $locations[$key] = $country; } $locations = array_filter($locations); $locations = array_unique($locations); $this->debug[] = 'locations loaded'; $this->location['range'] = array_merge($this->location['range'], $locations); } public function getRegions() { $regions = []; foreach ($this->query->posts as $key => $post) { // $post_translated_id = $post->ID; $post_translated_id = pll_get_post($post->ID); $destinations = tr_posts_field('charter_destinations', $post_translated_id); if (is_array($destinations)) : foreach ($destinations as $key => $destination) { # code... $destination_translated_id = pll_get_post($destination) ? pll_get_post($destination) : $destination; $regions[] = tr_posts_field('charter_region', $destination_translated_id)[0]; } endif; } $regions = array_filter($regions); $regions = array_unique($regions); asort($regions); $this->debug[] = 'regions loaded'; $this->region['range'] = array_merge($this->region['range'], $regions); } private function roundLength($length) { $length = array_filter($length); if (!empty($length) & intval($length) > 0) { $length_min = round(intval(min($length) - 1), 1, PHP_ROUND_HALF_DOWN); $length_min = floor($length_min); $length_max = round(intval(max($length) + 1), 1, PHP_ROUND_HALF_UP); $length_max = ceil($length_max); $this->debug[] = 'length rounded'; return ['min' => intval($length_min), 'max' => intval($length_max)]; } else { $this->debug[] = 'length round function get empty array'; return $this->length['range']; } } public function getBrands() { // TODO: get charter status // TODO: get charter query foreach ($this->query->posts as $key => $post) { $values[] = intval(get_post_meta($post->ID, 'charter_rate', true) ?: [0]); } $charter_query = []; foreach ($this->query->posts as $key => $post) { $charter_status = intval(get_post_meta($post->ID, 'available_for_charter', true)); if ($charter_status == get_query_var('charter') ?? 0) $charter_query[] = $post; } $terms = []; $args = array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'all'); foreach ($charter_query as $key => $post) { $terms[] = wp_get_post_terms($post->ID, 'brands', $args); } $brands = []; foreach ($terms as $term) { $brands[] = @$term[0]->name ?? $term->name; } $brands = array_filter($brands); $brands = array_unique($brands); asort($brands); $this->debug[] = 'brands loaded'; $this->brands['range'] = array_merge($this->brands['range'], $brands); return $this->brands['range']; } public function getGuests() { $guests_exact = []; foreach ($this->query->posts as $key => $post) { $guest_field = get_post_meta($post->ID, 'guests'); // $brand = array_shift($brands[0]); $guests_exact[$key] = @$guest_field[0] ? $guest_field[0] : 0; } $guests_exact = array_filter($guests_exact); $guests_exact = array_unique($guests_exact); foreach ($guests_exact as $value) { if ($value < 5) : $guests_selects[] = $value; else : $value = intval($value); $value = round($value / 5) * 5; $guests_selects[] = $value; endif; } $guests_selects = array_unique($guests_selects); asort($guests_selects); $this->debug[] = 'brands loaded'; $this->guests['range'] = array_merge($this->guests['range'], $guests_selects); return $this->guests['range']; } public function getYearRange() { $build_years = []; $result_array = []; foreach ($this->query->posts as $key => $post) { $build_years[] = get_post_meta($post->ID, 'year'); } foreach ($build_years as $key => $year) { $result_array[] = intval(array_shift($year)); } // var_dump($result_array); $build_years = array_filter($result_array); $build_years = array_unique($build_years); asort($build_years); $this->debug[] = 'years loaded'; $this->year['range']['min'] = min($build_years) > 1900 ? min($build_years) : 1990; $this->year['range']['max'] = max($build_years) > 2000 ? max($build_years) : date('Y'); return $this->year['range']; } public function getTypes() { $boat_types = []; foreach ($this->query->posts as $key => $post) { $boat_type = get_post_meta($post->ID, 'boat_type'); // $boat_type = array_shift($boat_type[0]); $boat_type = $boat_type[0]; // if ($boat_type == 'motor') $boat_type = pll__('motor', 'wn'); // if ($boat_type == 'sail') $boat_type = pll__('sail', 'wn'); $boat_types[$key] = $boat_type; } $boat_types = array_filter($boat_types); $boat_types = array_unique($boat_types); $this->debug[] = 'boat types loaded'; $this->types['range'] = array_merge($this->types['range'], $boat_types); return $this->types['range']; } } 1, 'show_stock' => 1, 'show_superyachts' => 1, 'show_brokerage' => 1, 'show_sold' => 1, 'show_archive' => 0, 'show_charter_only' => 0, 'show_sale_only' => 0, 'pagination' => 1, 'posts_per_page' => 9, ]; public $search_input = ''; const _NEW = 0; const _STOCK = 1; const _BROKERAGE = 2; const _SOLD = 3; const _ARCHIVE = 4; const _CONSTRUCTED = 5; const _SUPERYACHT = 6; function __construct($settings) { // Get query_vars if ($settings) $this->settings = $settings; $this->taxonomy = get_query_var('taxonomy') ?: ''; $this->terms = get_query_var('term') ?: ''; $this->yacht_status = get_query_var('yacht_status') ?: '2'; // Construct FilterController::Class parent::__construct(); // Build Conditions for Query $this->price_condition = $this::buildPrice(); $this->charterRate_condition = $this::buildCharterRate(); $this->length_condition = $this::buildLength(); $this->year_condition = $this::buildYear(); $this->location_condition = $this::buildLocation(); $this->types_condition = $this::buildTypes(); $this->brands_condition = $this::buildBrands(); $this->status_condition = $this::buildStatus(); $this->taxonomies_condition = $this::buildTaxonomies(); $this->guests_condition = $this::buildGuests(); $this->region_condition = $this::buildRegions(); $this->search_input = $this::buildSearch(); $this->sale_condition = $this::buildAvailability(); $this->charter_condition = $this::buildCharter(); // Generate WP_Query $this->query = $this::buildQuery(); } private function buildQuery() { $builder = new Builder(); $builder->addPostType('yacht'); $builder->createMainMetaQuery("AND"); if (!empty($this->status_condition)) $builder->addMetaQueryCollection($this->status_condition); if (!empty($this->charter_condition) && $this->settings['show_charter_only']) $builder->addMetaQueryCollection($this->charter_condition); if (!empty($this->region_condition) && $this->settings['show_charter_only']) $builder->addMetaQueryCollection($this->region_condition); if (!empty($this->charterRate_condition) && $this->settings['show_charter_only']) { $builder->addMetaQueryCollection($this->charterRate_condition); /*if( $_SERVER['REMOTE_ADDR'] == '77.95.33.48' ) { echo '
';
                echo 3;
                print_r($this->charterRate_condition);
                echo '
'; }*/ } if (!empty($this->length_condition)) $builder->addMetaQueryCollection($this->length_condition); if (!empty($this->guests_condition)) $builder->addMetaQueryCollection($this->guests_condition); if (!empty($this->year_condition)) $builder->addMetaQueryCollection($this->year_condition); if (!empty($this->search_input_condition)) $builder->addMetaQueryCollection($this->search_input_condition); if (!empty($this->location_condition) && $this->settings['show_charter_only']) $builder->addMetaQueryCollection($this->location_condition); if (!empty($this->price_condition) && $this->settings['show_charter_only']) { //$builder->addMetaQueryCollection($this->price_condition); /*if( $_SERVER['REMOTE_ADDR'] == '77.95.33.48' ) { echo '
';
                echo 1;
                print_r($this->price_condition);
                echo '
'; }*/ } else { $builder->addMetaQueryCollection($this->price_condition); /*if( $_SERVER['REMOTE_ADDR'] == '77.95.33.48' ) { echo '
';
                echo 2;
                print_r($this->price_condition);
                echo '
'; }*/ } if (!empty($this->types_condition)) $builder->addMetaQueryCollection($this->types_condition); if (!empty($this->sale_condition) && $this->settings['show_sale_only']) $builder->addMetaQueryCollection($this->sale_condition); $builder->createMainTaxonomyQuery("AND"); if (!empty($this->taxonomies_condition)) $builder->addTaxonomyQueryCollection($this->taxonomies_condition); if (!empty($this->brands_condition)) $builder->addTaxonomyQueryCollection($this->brands_condition); //search $builder->search($this->search_input); $args = $builder->getParameters(); if (function_exists('pll_current_language')) $args['lang'] = pll_current_language(); // Enable pagination if ($this->settings['pagination'] === 1) { $args['posts_per_page'] = $this->settings['posts_per_page'] ?: 9; $args['paged'] = get_query_var('paged'); if (isset($_GET['search-page']) && (int)$_GET['search-page'] >= 1) { $args['paged'] = (int)$_GET['search-page']; } } else { $args['posts_per_page'] = $this->settings['posts_per_page'] ?: 9; } // Order settings // $args['post_status'] = 'public'; $args['meta_query'][] = array( // 'relation' => 'AND', // 'order_status' => array( // 'key' => 'yacht_status', // ), 'order_length' => array( 'key' => 'length', 'type' => 'NUMERIC' ), ); // $args['orderby'] = array( // // 'order_status' => @$this->settings['order_settings'] ?: 'ASC', // 'order_length' => 'DESC', // ); if( $this->settings['show_charter_only'] ) : $args['orderby'] = 'relevance'; else : $args['meta_key'] = 'price'; $args['orderby'] = 'meta_value_num'; $args['order'] = 'DESC'; endif; $query = new WP_Query($args); return $query; } private function buildTaxonomies() { if ( !empty(get_query_var('term')) && !empty(get_query_var('taxonomy')) ) { $taxonomies_condition = new TaxonomyQueryCollection('OR'); $taxonomies_condition ->add(TaxonomyQuery::create($this->taxonomy, 'slug', $this->terms)); return $taxonomies_condition; } else { return null; } } private function buildCharterRate() { if (@$this->settings['show_charter_only'] === 1) : $field_name = 'charter_rate'; $charterRate_condition = new MetaQueryCollection('AND'); $charterRate_condition ->add(MetaQuery::create($field_name, $this->charter['current']['min'], '>=', 'NUMERIC')) ->add(MetaQuery::create($field_name, $this->charter['current']['max'], '<=', 'NUMERIC')); return $charterRate_condition; endif; } private function buildPrice() { //$field_name = 'price_cc_' . $this->currency; ///$price_wrapper = new MetaQueryCollection('OR'); //$price_condition = new MetaQueryCollection('AND'); $field_name = 'price'; $price_condition = new MetaQueryCollection('AND'); $price_condition ->add(MetaQuery::create($field_name, $this->prices['current']['min'], '>=', 'NUMERIC')) ->add(MetaQuery::create($field_name, $this->prices['current']['max'], '<=', 'NUMERIC')); // ->add(MetaQuery::create($field_name, [$this->prices['current']['min'], $this->prices['current']['max']], 'BETWEEN', 'NUMERIC')); // ->add(MetaQuery::create($field_name, $this->prices['current']['min'], '=', 'NUMERIC')) // ->add(MetaQuery::create($field_name, $this->prices['current']['max'], '=', 'NUMERIC')) // ->add(MetaQuery::create($field_name, '', '=', 'NUMERIC')) //$price_condition->add(MetaQuery::create($field_name, '', 'NOT EXISTS')); /*if( $_SERVER['REMOTE_ADDR'] == '77.95.33.48' ) { echo '
';
            var_dump($price_condition);
            echo '
'; }*/ //return $price_wrapper; return $price_condition; } private function buildYear() { $year_condition = new MetaQueryCollection('OR'); $year_condition ->add(MetaQuery::create('year', [$this->year['current']['min'], $this->year['current']['max']], 'BETWEEN', 'NUMERIC')) ->add(MetaQuery::create('year', '', 'NOT EXISTS')); return $year_condition; } private function buildLength() { $length_condition = new MetaQueryCollection('OR'); $length_condition ->add(MetaQuery::create('length', [$this->length['current']['min'], $this->length['current']['max']], 'BETWEEN', 'NUMERIC')) ->add(MetaQuery::create('length', '', 'NOT EXISTS')); return $length_condition; } private function buildStatus() { $status_condition = new MetaQueryCollection('OR'); if ($this->settings['show_new'] === 1) $status_condition->add(MetaQuery::create('yacht_status', self::_NEW, '=')); if ($this->settings['show_superyachts'] === 1) $status_condition->add(MetaQuery::create('yacht_status', self::_SUPERYACHT, '=')); if ($this->settings['show_stock'] === 1) $status_condition->add(MetaQuery::create('yacht_status', self::_STOCK, '=')); if ($this->settings['show_brokerage'] === 1) $status_condition->add(MetaQuery::create('yacht_status', self::_BROKERAGE, '=')); if ($this->settings['show_sold'] === 1) $status_condition->add(MetaQuery::create('yacht_status', self::_SOLD, '=')); if ($this->settings['show_archive'] === 1) $status_condition->add(MetaQuery::create('yacht_status', self::_ARCHIVE, '=')); return $status_condition; } private function buildLocation() { if ($this->location['current'] != $this->location['range'][0]) { $location_condition = new MetaQueryCollection('OR'); $location_condition ->add(MetaQuery::create('country', $this->location['current'], '=')) ->add(MetaQuery::create('country', '', 'NOT EXISTS')); return $location_condition; } else { return null; } } private function buildRegions() { /** * Get current region name and compares to destinations. Finds ID and put in query builder; */ // if ($this->region['current'] != $this->region['range'][0]) { if (1 == 1) { // NOTE: the condition above was originally // `$this->region['current'] != $this->region['range'][0]` // (i.e. "only do this when a region filter is actually // selected"), but got hard-disabled to `1 == 1` at some point, // so this expensive destination scan now runs unconditionally // on every single yacht search/listing request. Restoring the // original condition would change what WHERE clause gets built // (an empty MetaQueryCollection is still added to the query // builder today) and that's not something that can be safely // verified without a live WP install, so behaviour is left // exactly as-is here. Instead, the expensive part - scanning // every "destination" post and reading its charter_region meta // one post at a time - is cached, since that mapping only // changes when destinations are edited, not per visitor. $regions = get_transient(self::getDestinationRegionsCacheKey()); if (!is_array($regions)) { $destinations = get_posts([ 'numberposts' => -1, 'post_type' => 'destination', ]); $regions = []; foreach ($destinations as $key => $destination) { $regions[$destination->ID] = tr_posts_field('charter_region', $destination->ID); } set_transient(self::getDestinationRegionsCacheKey(), $regions, 6 * HOUR_IN_SECONDS); } // [id of destination] with that region $destinations_search = []; foreach ($regions as $id => $destination_regions) { if (is_array($destination_regions)) foreach ($destination_regions as $region_name) { if ($region_name == $this->region['current']) { $destinations_search[] = $id; } } } $region_condition = new MetaQueryCollection('OR'); foreach ($destinations_search as $key => $destination_id) { pll_current_language() == 'en' ? $lang = 'ru' : $lang = 'en'; $destination_id_lang_fallback = pll_get_post($destination_id, $lang); $region_condition ->add(MetaQuery::create('charter_destinations', $destination_id, 'LIKE')); $region_condition ->add(MetaQuery::create('charter_destinations', $destination_id_lang_fallback, 'LIKE')); } return $region_condition; } else { return null; } } private static function getDestinationRegionsCacheKey() { $lang = function_exists('pll_current_language') ? pll_current_language() : 'default'; return 'wn_destination_regions_' . md5($lang); } /** * Clear the cached destination -> region-name map. Hooked to * save/delete of "destination" posts in includes/init/functions.php. */ public static function clearDestinationRegionsCache() { global $wpdb; $like = $wpdb->esc_like('_transient_wn_destination_regions_') . '%'; $names = $wpdb->get_col($wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", $like )); foreach ($names as $name) { delete_option($name); delete_option(str_replace('_transient_', '_transient_timeout_', $name)); } } private function buildBrands() { if (isset($this->brands['current']) && $this->brands['current'] != $this->brands['range'][0]) { $taxonomies_condition = new TaxonomyQueryCollection('OR'); $brand = strtolower($this->brands['current']); // var_dump($brand); // var_dump(get_taxonomy('brands')); $taxonomies_condition ->add(TaxonomyQuery::create('brands', 'name', $this->brands['current'], true, 'IN')); return $taxonomies_condition; } else { return null; } } public function pagination() { if (!isset($this->query)) : global $wp_query; $query = $wp_query; else : $query = $this->query; endif; $big = 999999999; $total = isset($query->max_num_pages) ? $query->max_num_pages : 1; $args = array( 'format' => (isset($_GET['search_input']) && !empty($_GET['search_input']) ? '?search-page=' : '?page=') . '%#%', 'current' => max(1, (isset($_GET['search-page']) && !empty($_GET['search-page']) ? (int)$_GET['search-page'] : get_query_var('paged'))), 'prev_next' => true, 'prev_text' => 'Previous page', 'next_text' => 'Next page', 'total' => $total ); if (!isset($_GET['search_input']) || empty($_GET['search_input'])) { if (get_option('permalink_structure')) : $args['base'] = str_replace($big, '%#%', get_pagenum_link($big)); else : $args['base'] = add_query_arg('page', '%#%'); endif; } // echo previous_posts_link('Newer posts'); echo paginate_links($args); // echo next_posts_link('Older posts'); } private function buildGuests() { if (isset($this->guests['current']) && $this->guests['current'] != $this->guests['range'][0]) : $guests_condition = new MetaQueryCollection('OR'); $guests_condition ->add(MetaQuery::create('guests', [0, $this->guests['current']], 'BETWEEN', 'NUMERIC')) ->add(MetaQuery::create('guests', '', 'NOT EXISTS')); return $guests_condition; endif; } private function buildTypes() { if (isset($this->types['current']) && $this->types['current'] != $this->types['range'][0]) { $types_condition = new MetaQueryCollection('OR'); $types_condition ->add(MetaQuery::create('boat_type', $this->types['current'], '=')) ->add(MetaQuery::create('boat_type', pll__($this->types['current']), '=')) ->add(MetaQuery::create('boat_type', '', 'NOT EXISTS')); return $types_condition; } else { return null; } } private function buildSearch() { if (isset($this->search_input) && !empty($this->search_input)) { return $this->search_input; } else { return null; } } private function buildCharter() { if (@$this->settings['show_charter_only'] === 1) : $charter_condition = new MetaQueryCollection('OR'); $charter_condition ->add(MetaQuery::create('available_for_charter', 0, '!=')); return $charter_condition; else : return null; endif; } private function buildAvailability() { if (@$this->settings['show_sale_only'] === 1) : $sale_condition = new MetaQueryCollection('OR'); $sale_condition->add(MetaQuery::create('available_for_sale', 1, '=')); return $sale_condition; else : return null; endif; } } '; // $html .= '
'; // $html .= 'Broker PDF'; // $html .= 'Overwrite PDF'; // $html .= '
'; // $html .= ''; // echo $html; // } // } /*===== End of CUSTOM BUTTON AND FUNCTION FOR GENERATE PDF FILE ======*/ /*=========================================================== = PRINCESS YACHT CLASSES HELPER CLASS = ===========================================================*/ class Yacht { /** * * Settings * */ // New yachts taxonomy to display in catalog const CATALOG_TAXONOMY = 'classes'; // Currency symbol const EURO = "€"; const DOLLAR = " $"; const RUB = " ₽"; const POUND = " £"; const DEFAULT_CURRENCY = "euro"; const NEW_YACHT = 'Яхта под заказ'; const STOCK_YACHT = 'Яхта в наличии'; const USED_YACHT = 'Брокеражная яхта'; const SOLD_YACHT = 'Продано'; const ARCHIVE_YACHT = 'В архиве'; const CONSTRUCTED_YACHT = 'Флот'; const SUPERYACHT = 'Суперъяхта'; // Declare variable types public $post_type; public $ID = ''; public $featured_image = ''; public $media = ''; public $post_title = ''; public $status = ''; public $status_label = ''; public $post_content = ''; public $fields = ''; public $plans = ''; public $dedicated_person = ''; public $options = ''; public $pdf = ''; public $notes = ''; public $reviews = ''; public $profile_image = ''; public $terms = ''; function __construct() { $this->featured_image = self::getFeaturedImage(); $this->media = new YachtMedia; $this->post_title = get_the_title(); $this->options = new YachtOptions(); $this->status = self::getStatus(); $this->post_content = self::getPostContent(); $this->fields = new YachtFields; $this->plans = self::getPlans(); $this->pdf = tr_posts_field('pdf'); $this->files = tr_posts_field('reviews_files'); $this->related = self::getRelated(); $this->terms = [ wp_get_post_terms($this->ID, 'series'), wp_get_post_terms($this->ID, 'tags'), wp_get_post_terms($this->ID, 'brands'), ]; } public function getStatusClass($status = ''): string { if (empty($status)) $status = $this::getStatus(); switch ($status) { case 0: $status_class = 'yacht-card__new'; break; case 1: $status_class = 'yacht-card__stock'; break; case 2: $status_class = 'yacht-card__brokerage'; break; case 3: $status_class = 'yacht-card__sold'; break; case 4: $status_class = 'yacht-card__archive'; break; case 5: $status_class = 'yacht-card__constructed'; break; case 6: $status_class = 'yacht-card__superyachts'; break; default: $status_class = 'yacht-card__brokerage'; break; } return $status_class; } private function getRelated(): array { $related = []; $related = tr_posts_field('recommendations'); $related_id = []; if (is_array($related)) { foreach ($related as $key => $value) { $related_id[] = $value['select_yacht']; } } return $related_id; } private function getPost(): object { global $post; return $post; } private function getContent($field = ''): string { if ($content = tr_posts_field($field)) : return $content; else : return ''; endif; } private function getPostContent(): string { if (tr_posts_field('post_content')) { $post_content = tr_posts_field('post_content'); $post_content = apply_filters('the_content', $post_content);; } else { $post_content = ''; } return $post_content; } public function getStatus(): int { return intval(tr_posts_field('yacht_status')); } public function getYachtID(): int { return get_the_id(); } public function getProfileImage() { $image = ''; $html = ''; $alt = 'Профиль ' . get_the_title(); if ($image_id = tr_posts_field('profile_image')) { $profile_width = tr_posts_field('profile_width') ?: '100'; } else { $profile_width = '100'; } $image = wp_get_attachment_image_url($image_id, 'profile_thumbnail'); $srcset = get_attachment_image_srcset($image_id); $alt = get_post_meta($image_id, '_wp_attachment_image_alt', true) ?: $alt; // return $image; $html .= << HTML; return $html; } public function getFeaturedImage($tag = 1): string { $id = tr_posts_field('featured_image') ?: tr_posts_field('exterior')[0]; $alt = get_post_meta($id, '_wp_attachment_image_alt', true) ?: 'Яхта ' . get_the_title() . ' | ID: ' . get_the_id(); return wp_get_attachment_image($id, 'half_width'); // if ($tag == 0) { // return wp_get_attachment_image_url($id, 'full_width'); // } else { // return get_responsive_image($id, 'half_width', 'yacht-featured-image', $alt, get_permalink()); // } } private function getPlans(): array { tr_posts_field('plans') ? $plans = tr_posts_field('plans') : $plans = []; return $plans; } private function getHighlights(): array { tr_posts_field('highlights') ? $highlights = tr_posts_field('highlights') : $highlights = []; return $highlights; } public function getStatusLabel($status = ''): string { if (!$status) $status = $this->getStatus(); switch ($status) { case 0: $label = $this::NEW_YACHT; break; case 1: $label = $this::STOCK_YACHT; break; case 2: $label = $this::USED_YACHT; break; case 3: $label = $this::SOLD_YACHT; break; case 4: $label = $this::ARCHIVE_YACHT; break; case 5: $label = $this::CONSTRUCTED_YACHT; break; case 6: $label = $this::SUPERYACHT; break; default: $label = $this::USED_YACHT; break; } return $label; } } require_once('includes/YachtFields.php'); require_once('includes/YachtCard.php'); require_once('includes/YachtCraft.php'); require_once('includes/YachtMedia.php'); require_once('includes/YachtOptions.php'); require_once('includes/YachtProfile.php'); settings = $settings; $this->search_input = get_search_query(); // Construct FilterController::Class parent::__construct(); // Generate WP_Query $this->query = $this::buildQuery(); } private function buildQuery() { $builder = new Builder(); $post_types = array_diff_key(get_post_types(), array_flip(['yacht'])); foreach ($post_types as $post_type) { $builder->addPostType($post_type); } //search $builder->search(get_search_query()); $args = $builder->getParameters(); if (function_exists('pll_current_language')) $args['lang'] = pll_current_language(); // Enable pagination if ($this->settings['pagination'] === 1) { $args['posts_per_page'] = $this->settings['posts_per_page'] ?: 9; $args['paged'] = get_query_var('paged'); } else { $args['posts_per_page'] = $this->settings['posts_per_page'] ?: 9; } $query = new WP_Query($args); return $query; } public function pagination() { if (!isset($this->query)) : global $wp_query; $query = $wp_query; else : $query = $this->query; endif; $big = 999999999; $total = isset($query->max_num_pages) ? $query->max_num_pages : 1; $args = array( 'format' => '?page=%#%', 'current' => max(1, get_query_var('paged')), 'prev_next' => true, 'prev_text' => 'Previous page', 'next_text' => 'Next page', 'total' => $total ); if (get_option('permalink_structure')) : $args['base'] = str_replace($big, '%#%', get_pagenum_link($big)); else : $args['base'] = add_query_arg('page', '%#%'); endif; // echo previous_posts_link('Newer posts'); echo paginate_links($args); // echo next_posts_link('Older posts'); } } useJson(); // echo $sitesetup->open(); // $text = function () use ($sitesetup) { // echo $sitesetup->textarea('Header scripts')->setHelp('Put your header js scripts here'); // echo $sitesetup->textarea('Footer scripts')->setHelp('Put your footer js scripts here'); // echo $sitesetup->text('Facebook URL')->setHelp('Facebook page URL'); // echo $sitesetup->text('YouTube URL')->setHelp('YouTube page URL'); // echo $sitesetup->text('Instagram URL')->setHelp('Instagram page URL'); // echo $sitesetup->text('Vimeo URL')->setHelp('Vimeo page URL'); // echo $sitesetup->editor('Main address block'); // echo $sitesetup->text('Main phone number')->setHelp('+79999999999'); // echo $sitesetup->text('Main Email address')->setHelp('info@fairline-russia.com'); // }; // $statuses = function () use ($sitesetup) { // echo $sitesetup->text('Brokerage')->setSetting('default', 'Брокераж'); // echo $sitesetup->text('Stock')->setSetting('default', 'В наличии'); // echo $sitesetup->text('New yacht')->setSetting('default', 'Под заказ'); // echo $sitesetup->text('Sold')->setSetting('default', 'Продано'); // echo $sitesetup->text('Archive')->setSetting('default', 'Архив'); // }; // $filter = function () use ($sitesetup) { // echo $sitesetup->text('Filter min year')->setType('number')->setSetting('default', 1990);; // echo $sitesetup->text('Filter max year')->setType('number')->setSetting('default', date('Y') + 1);; // }; // $texts = function () use ($sitesetup) { // echo $sitesetup->text('News page header'); // echo $sitesetup->editor('News page text'); // echo $sitesetup->text('Constructed header'); // echo $sitesetup->editor('Constructed page text'); // echo $sitesetup->text('Related header'); // echo $sitesetup->editor('Related text'); // echo $sitesetup->text('Team header'); // echo $sitesetup->editor('Team text'); // }; // // Save // $save = $sitesetup->submit('Save'); // $seo = function () use ($sitesetup) { // echo $sitesetup->text('Brand title prefix') // ->setHelp(' for brand taxonomy -> prefix BRANDNAME | postfix'); // echo $sitesetup->textarea('Brand description'); // echo $sitesetup->text('Series title prefix') // ->setHelp(' for series taxonomy -> prefix SERIES | postfix'); // echo $sitesetup->textarea('Series description'); // echo $sitesetup->text('Tags title prefix') // ->setHelp(' for tags taxonomy -> prefix TAG | postfix'); // echo $sitesetup->textarea('Series description'); // echo $sitesetup->text('Team SEO title'); // echo $sitesetup->text('Team SEO description'); // }; // // Layout // tr_tabs()->setSidebar($save) // ->addTab('Site options', $text) // ->addTab('SEO Options', $seo) // ->addTab('Statuses', $statuses) // ->addTab('Filter options', $filter) // ->addTab('Additional', $texts) // ->render('box'); // echo $sitesetup->close(); $settings = [ 'capability' => 'administrator', 'position' => 99, 'view_file' => get_stylesheet_directory() . '/app/Views/options.php' ]; $settings_page = tr_page('wn_setting', 'index', 'WN Settings', $settings); $settings_page->setIcon('equalizer'); setIcon('book') // ->setSlug('news') // ->setTitlePlaceholder('Enter Article Title') // ->setEditorForm(function () { // $form = tr_form(); // echo $form->text('Name'); // }); tr_meta_box('Post settings')->addScreen('post'); function add_meta_content_post_settings() { $form = tr_form(); echo '

only if "Standard Editor" is enabled

'; echo $form->repeater('Slides')->setFields([ $form->text('Headline (left)'), $form->text('Headline (right)'), $form->image('Slide image'), $form->text('Button text'), $form->text('Custom link'), $form->search('Search')->setPostType('any') ]); echo $form->text('Subheader'); }